/*
 * Copyright (C) The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.barcodereader;

import android.content.Context;
import androidx.annotation.UiThread;

import com.google.barcodereader.ui.camera.GraphicOverlay;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.Tracker;
import com.google.android.gms.vision.barcode.Barcode;

import android.graphics.Rect;
import android.graphics.Point;

/**
 * Generic tracker which is used for tracking or reading a barcode (and can really be used for
 * any type of item).  This is used to receive newly detected items, add a graphical representation
 * to an overlay, update the graphics as the item changes, and remove the graphics when the item
 * goes away.
 */
public class BarcodeGraphicTracker extends Tracker<Barcode> {
    private GraphicOverlay<BarcodeGraphic> mOverlay;
    private BarcodeGraphic mGraphic;
    private BarcodeUpdateListener mBarcodeUpdateListener;

    /**
     * Consume the item instance detected from an Activity or Fragment level by implementing the
     * BarcodeUpdateListener interface method onBarcodeDetected.
     */
    public interface BarcodeUpdateListener {
        void onBarcodeDetected(Barcode barcode);
        void onBarcodeInCenter(Barcode barcode);
    }


    boolean isBarcodeBetweenBorders(Barcode barcode){
        float width = mOverlay.getPreviewWidth();
        float height = mOverlay.getPreviewHeight();

        float topBorder     = mOverlay.getTopBorder(width, height);
        float bottomBorder  = mOverlay.getBottomBorder(width, height);
        float leftBorder    = mOverlay.getLeftBorder(width, height);
        float rightBorder   = mOverlay.getRightBorder(width, height);

        Point[] points = barcode.cornerPoints;
        for(int i = 0; i < 4; i++){
            if (points[i].x < leftBorder || 
                points[i].x > rightBorder || 
                points[i].y < topBorder || 
                points[i].y > bottomBorder) return false;
        }
        return true;
    }

    boolean isBarcodeAtCenter(Barcode barcode){
        float width = mOverlay.getPreviewWidth();
        float height = mOverlay.getPreviewHeight();
        
        float verticalCenter = width / 2;
        float horizontalCenter = height / 2;
        Point[] points = barcode.cornerPoints;

        float barcodeVecticalCenter = 0;
        float barcodeHorizontalCanter = 0;
        for(int i = 0; i < 4; i++){
            barcodeHorizontalCanter += points[i].x;
            barcodeVecticalCenter   += points[i].y;
        }
        barcodeHorizontalCanter/=4;
        barcodeVecticalCenter/=4;

        float delta = Math.min(width, height) * 0.25f;

        return Math.pow(verticalCenter - barcodeVecticalCenter, 2) + Math.pow(horizontalCenter - barcodeHorizontalCanter, 2) < delta*delta;


    }


    BarcodeGraphicTracker(GraphicOverlay<BarcodeGraphic> mOverlay, BarcodeGraphic mGraphic,
                          Context context) {
        this.mOverlay = mOverlay;
        this.mGraphic = mGraphic;



        if (context instanceof BarcodeUpdateListener) {
            this.mBarcodeUpdateListener = (BarcodeUpdateListener) context;
        } else {
            throw new RuntimeException("Hosting activity must implement BarcodeUpdateListener");
        }
    }

    /**
     * Start tracking the detected item instance within the item overlay.
     */

    boolean detected = false;

    @Override
    public void onNewItem(int id, Barcode item) {
        mGraphic.setId(id);
        if (isBarcodeBetweenBorders(item) && !detected){
            mBarcodeUpdateListener.onBarcodeDetected(item);
            detected = true;
        }
    }

    /**
     * Update the position/characteristics of the item within the overlay.
     */
    @Override
    public void onUpdate(Detector.Detections<Barcode> detectionResults, Barcode item) {
        boolean betweenBorders = isBarcodeBetweenBorders(item);
        if (betweenBorders && !detected){
            mBarcodeUpdateListener.onBarcodeDetected(item);
            detected = true;
        }


        if (betweenBorders){
            if (isBarcodeAtCenter(item)){
                mBarcodeUpdateListener.onBarcodeInCenter(item);
            }
            mOverlay.add(mGraphic);
            mGraphic.updateItem(item);
        }else{
            mOverlay.remove(mGraphic);
        }
       
    }

    /**
     * Hide the graphic when the corresponding object was not detected.  This can happen for
     * intermediate frames temporarily, for example if the object was momentarily blocked from
     * view.
     */
    @Override
    public void onMissing(Detector.Detections<Barcode> detectionResults) {
        mOverlay.remove(mGraphic);
    }

    /**
     * Called when the item is assumed to be gone for good. Remove the graphic annotation from
     * the overlay.
     */
    @Override
    public void onDone() {
        mOverlay.remove(mGraphic);
    }
}
